package org.csu.softwaremetrics_demo.entity.executor;

import org.csu.softwaremetrics_demo.entity.common.CKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.common.LKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.common.TraditionMetricSingleClass;
import org.csu.softwaremetrics_demo.metric.ClassInfo;
import org.csu.softwaremetrics_demo.metric.Metric;
import org.csu.softwaremetrics_demo.util.ColorLoggerUtils;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FileASTRequestor;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * 度量执行器类，负责执行各种度量计算并收集结果
 * 泛型 <Result> 代表度量结果类型，<SingleClassMetric> 代表单个类度量结果类型
 *
 * @author Jukomu
 * @since 2023/4/6
 */
public class MetricsExecutor<Result extends org.csu.softwaremetrics_demo.entity.result.Result, SingleClassMetric> extends FileASTRequestor {

    private Result result;
    private Callable<List<Metric<SingleClassMetric>>> metrics;

    private static final ColorLoggerUtils logger = ColorLoggerUtils.getLogger(MetricsExecutor.class);

    /**
     * 构造函数，初始化度量执行器
     *
     * @param metrics 度量计算器列表的提供者
     * @param type 结果类型的Class对象
     */
    public MetricsExecutor(Callable<List<Metric<SingleClassMetric>>> metrics, Class<Result> type) {
        this.metrics = metrics;
        try {
            this.result = type.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create instance of type " + type.getName(), e);
        }
    }

    /**
     * 处理AST并执行度量计算
     *
     * @param sourceFilePath 源文件路径
     * @param cu 编译单元
     */
    @Override
    public void acceptAST(String sourceFilePath, CompilationUnit cu) {
        SingleClassMetric singleMetric = null;

        try {
            // 解析类信息
            ClassInfo info = new ClassInfo();
            cu.accept(info);
            if (info.getClassName() == null) return;

            // 创建适当类型的单类度量结果对象
            singleMetric = createSingleMetric(sourceFilePath, info);
            if (singleMetric == null) return;

            // 计算代码行数
            int loc = new LOCCalculator().calculate(Files.newInputStream(Paths.get(sourceFilePath)));
            setLoc(singleMetric, loc);

            // 执行所有度量计算
            for (Metric<SingleClassMetric> visitor : metrics.call()) {
                visitor.execute(cu, singleMetric, this.result);
                visitor.setSingleMetric(singleMetric);
            }

            // 添加结果
            this.result.add(singleMetric);
        } catch (Exception e) {
            handleError(singleMetric, sourceFilePath, e);
        }
    }

    /**
     * 根据泛型类型创建适当的单类度量结果对象
     *
     * @param sourceFilePath 源文件路径
     * @param info 类信息
     * @return 单类度量结果对象
     */
    @SuppressWarnings("unchecked")
    private SingleClassMetric createSingleMetric(String sourceFilePath, ClassInfo info) {
        try {
            List<Metric<SingleClassMetric>> metricsList = metrics.call();
            if (!metricsList.isEmpty()) {
                // 获取第一个度量指标的泛型参数类型
                Class<?> metricType = getMetricParameterType(metricsList.get(0));

                if (metricType.equals(CKMetricSingleClass.class)) {
                    return (SingleClassMetric) new CKMetricSingleClass(sourceFilePath, info.getClassName(), info.getType());
                } else if (metricType.equals(LKMetricSingleClass.class)) {
                    return (SingleClassMetric) new LKMetricSingleClass(sourceFilePath, info.getClassName(), info.getType());
                } else if (metricType.equals(TraditionMetricSingleClass.class)) {
                    return (SingleClassMetric) new TraditionMetricSingleClass(sourceFilePath, info.getClassName(), info.getType());
                }
            }
        } catch (Exception e) {
            logger.error("Failed to create single metric", e);
        }
        return null;
    }

    /**
     * 获取度量指标的泛型参数类型
     *
     * @param metric 度量指标实例
     * @return 泛型参数的Class对象
     */
    private Class<?> getMetricParameterType(Metric<SingleClassMetric> metric) {
        try {
            // 获取Metric接口的泛型参数类型
            return (Class<?>) ((java.lang.reflect.ParameterizedType) metric.getClass()
                    .getGenericInterfaces()[0]).getActualTypeArguments()[0];
        } catch (Exception e) {
            logger.error("Failed to get metric parameter type", e);
            return null;
        }
    }

    /**
     * 设置代码行数
     *
     * @param singleMetric 单类度量结果对象
     * @param loc 代码行数
     */
    private void setLoc(SingleClassMetric singleMetric, int loc) {
        try {
            // 通过反射调用setLoc方法
            singleMetric.getClass().getMethod("setLoc", int.class).invoke(singleMetric, loc);
        } catch (Exception e) {
            logger.error("Failed to set LOC for " + singleMetric.getClass().getSimpleName());
        }
    }

    /**
     * 处理错误情况
     *
     * @param singleMetric 单类度量结果对象
     * @param sourceFilePath 源文件路径
     * @param e 异常
     */
    private void handleError(SingleClassMetric singleMetric, String sourceFilePath, Exception e) {
        if (singleMetric != null) {
            try {
                // 通过反射调用error方法
                singleMetric.getClass().getMethod("error").invoke(singleMetric);
            } catch (Exception ex) {
                logger.error("Failed to call error method", ex);
            }
        }
        logger.error("Error in " + sourceFilePath, e);
    }

    /**
     * 获取度量结果
     *
     * @return 度量结果
     */
    public Result getResult() {
        return result;
    }

}
